#ifndef __C_PROC_H__
#define __C_PROC_H__

#include "std/list.h"
#include "std/avltree.h"
#include "fs/fs.h"
#include "kernel/vma.h"
#include "kernel/spinlock.h"
#include "kernel/wait.h"
#include "arch/sys.h"

#ifdef __cplusplus
extern "C" {
#endif

// tss structure for intel chip
struct tss_stru
{
	unsigned short		backlink, backlinkh;
	unsigned int		esp0;
	unsigned short		ss0, ss0h;
	unsigned int		esp1;
	unsigned short		ss1, ss1h;
	unsigned int		esp2;
	unsigned short		ss2, ss2h;
	unsigned int		cr3;
	unsigned int		eip;
	unsigned int		eflags;
	unsigned int		eax, ecx, edx, ebx;
	unsigned int		esp;
	unsigned int		ebp;
	unsigned int		esi;
	unsigned int		edi;
	unsigned short		es, esh;
	unsigned short		cs, csh;
	unsigned short		ss, ssh;
	unsigned short		ds, dsh;
	unsigned short		fs, fsh;
	unsigned short		gs, gsh;
	unsigned short		ldt, ldth;
	unsigned short		trace, bitmap;
	unsigned int		iobitmap_end;
} PACKED;

typedef struct tss_stru tss_stru_t;

// the only tss in the system (intel chip)
extern tss_stru_t main_tss;

// the stack (2 pages) for idle thread
// note that all initialization of the system
// is done in the idle thread
extern void* idle_thread_stack;

// bit 1,2 is reserved
#define SA_SHIRQ			(4)
#define SA_INTERRUPT		(8)

typedef uint pid_t;
typedef uint tid_t;
struct dentry;
struct task_struct;
struct thread_struct;

typedef struct mm_struct
{
	uint*		page_dir;
	vma_mgr_t	userspace;
	vma_mgr_t*	krnlspace;
}
mm_struct_t;

typedef struct fs_data
{
	struct dentry* root;
	struct dentry* pwd;
}
fs_data_t;

typedef struct task_struct
{
	listnode_t	ownerlist;
	avl_node_t	avlnode;
	listnode_t	thdlist;

	pid_t		pid;				// unique id for the task
	uint		thdcnt;				// count of threads

	mm_struct_t	mm;
	fs_data_t	fs_data;
}
task_t;

typedef int (*thdfunc_t)(void*);

typedef struct thread_struct
{
	listnode_t	ownerlist;
	avl_node_t	avlnode;
	listnode_t	sched_list;

	tid_t		tid;				// unique id for the thread
	task_t*		task;				// current task
	uint		flags;				// flags
	struct thread_struct* parents;	// parents
	ushort		priority;			// priority of the thread
	ushort		state;				// thread state

	thdfunc_t	start_routine;		// thread function entry
	void*		arguments;			// thread function arguments

	thread_arch_data_t arch_data;	// architecture specific data
}
thread_t;

typedef struct sched_node
{
	listnode_t	fifo_list;			// for SCHED_FIFO
	listnode_t	rr_list;			// for SCHED_RR
}
sched_node_t;

extern thread_t* current_thd;
#define get_current()	(current_thd)
#define current			(current_thd)

// thread stack size
#define THD_STACK_SZ		(PAGE_SZ * 2)

// thread max priority
#define THD_PRIORITY_MAX	(100)

// thread state
#define THD_STAT_UNKNOWN			(0)
#define THD_STAT_RUNNING			(1)
#define THD_STAT_INTERRUPTABLE		(2)
#define THD_STAT_UNINTERRUPTABLE	(3)
#define THD_STAT_CREATION			(4)
#define THD_STAT_ZOMBIE				(5)

#define is_thd_running(t)	(THD_STAT_RUNNING == (t)->state)

// scheduler policy
#define THD_SCHED_POLICY_OTHER			(1)
#define THD_SCHED_POLICY_RR				(2)
#define THD_SCHED_POLICY_FIFO			(4)
#define THD_SCHED_POLICY_MASK	\
	(THD_SCHED_POLICY_OTHER | THD_SCHED_POLICY_RR | THD_SCHED_POLICY_FIFO)

// need resched
#define THD_FLAG_NEED_RESCHED			(8)

// thread joinable (or detached if not set)
#define THD_FLAG_JOINABLE				(16)

// conduct sched check and do
// schedule in timer tasklet
void handle_sched(void);

// request for a resched
bool request_resched(void);

// conduct a schedule
void schedule(void);

// set the state of a thread
bool set_thread_state(thread_t *thd, uint newstate, bool preempt);
#define set_current_state(_st, _preempt) \
	set_thread_state(current, (_st), (_preempt))

// create a thread
int thread_create(thread_t** pthd, thdfunc_t start_routine, void* arg);

// exit a thread
void thread_exit(int errcode);

// set thread state of detach
int thread_setdetachstate(thread_t* thd, bool detach);

// make a thread sleep
void thread_sleep(thread_t** thd, bool interruptable);
#define thread_sleep_interruptable(thd)	thread_sleep((thd), true)
#define thread_sleep_uninterruptable(thd) thread_sleep((thd), false)

// make a thread wakeup
#define THD_OPE_WAKEUP_INTERRUPTABLE		(WQ_FLAG_WAKEUP_INTERRUPTABLE)
#define THD_OPE_WAKEUP_UNINTERRUPTABLE		(WQ_FLAG_WAKEUP_UNINTERRUPTABLE)
#define THD_OPE_WAKEUP_PREEMPT				(WQ_FLAG_WAKEUP_PREEMPT)
#define THD_OPE_WAKEUP_SYNCHRONOUS			(WQ_FLAG_WAKEUP_SYNCHRONOUS)

bool thread_wakeup(thread_t* thd, uint flags);
#define thread_wakeup_interruptable(thd) \
	thread_wakeup((thd), THD_OPE_WAKEUP_INTERRUPTABLE)
#define thread_wakeup_uninterruptable(thd) \
	thread_wakeup((thd), THD_OPE_WAKEUP_UNINTERRUPTABLE)

// global initializor
void global_init_proc_module(void);

#ifdef __cplusplus
}
#endif
#endif
/* EOF */
